#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <atomic>
#include <condition_variable>
#include <functional>
#include <iostream> // test
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <unordered_map>
#include <vector>

class Any;
class Semaphore;
class Result;
class Task;
class Thread;
enum class PoolMode;
class ThreadPool;

/**
 * Any class：可以接受任意类型的数据
 */
class Any
{
private:
    /**
     * 基类类型
     */
    class Base
    {
    public:
        virtual ~Base() = default;
    };

    /**
     * 派生类类型
     */
    template<typename T>
    class Derive : public Base
    {
    public:
        T data_; // 保存了任意的其它类型

    public:
        Derive( T data ) : data_( data ) {}
    };

private:
    std::unique_ptr<Base> base_; // 定义一个基类指针

public:
    Any()                        = default;
    ~Any()                       = default;
    Any( const Any& )            = delete;
    Any& operator=( const Any& ) = delete;
    Any( Any&& )                 = default;
    Any& operator=( Any&& )      = default;

    /* 这个构造函数可以让 Any 类型接收任意其它的数据 */
    template<typename T>
    Any( T data ) : base_( std::make_unique<Derive<T>>( data ) )
    {}

    /* 这个方法能把 Any 对象里面存储的 data 数据取出来 */
    template<typename T>
    T cast_()
    {
        // 基类指针 ==> 派生类指针 RTTI
        Derive<T>* pD = dynamic_cast<Derive<T>*>( base_.get() );
        if ( pD == nullptr ) {
            throw "type is unmatch";
        }
        return pD->data_;
    }
};

/**
 * 信号量类
 */
class Semaphore
{
private:
    int                     resLimit_;
    std::mutex              mtx_;
    std::condition_variable cond_;

public:
    Semaphore( int limit = 0 ) : resLimit_( limit ) {}
    ~Semaphore() = default;

    /* 获取一个信号量资源 */
    void wait()
    {
        std::unique_lock<std::mutex> lock( mtx_ );
        // 等待信号量有资源，没有资源的话，会阻塞当前线程
        cond_.wait( lock, [&]() -> bool { return resLimit_ > 0; } );
        resLimit_--;
    }

    /* 增加一个信号量资源 */
    void post()
    {
        std::unique_lock<std::mutex> lock( mtx_ );
        resLimit_++;
        // Linux 下 condition_variable 的析构函数什么也没做
        // 导致这里状态已失效，无故阻塞
        cond_.notify_all(); // 等待状态，释放 mutex 锁，通知条件变量 wait 的地方，可以起来干活了
    }
};

/**
 * 实现接受提交到线程池的 task 任务执行完成后的返回值类型 Result
 */
class Result
{
private:
    Any                   any_;     // 存储任务的返回值
    Semaphore             sem_;     // 线程通信信号量
    std::shared_ptr<Task> task_;    // 指向对应获取返回值的任务对象
    std::atomic_bool      isValid_; // 返回值是否有效

public:
    Result( std::shared_ptr<Task> task, bool isValid = true );
    ~Result() = default;

    /* 获取任务执行完的返回值 */
    void setVal( Any any );

    /* 用户调用这个方法获取 task 的返回值 */
    Any get();
};

/**
 * 任务抽象基类
 */
class Task
{
private:
    Result* result_; // Result 对象的生命周期 > Task

public:
    Task();
    ~Task() = default;

    void exec();

    void setResult( Result* res );

    /* 用户可以自定义任意任务类型，从 Task 继承，重写 `run` 方法，实现自定义任务处理 */
    virtual Any run() = 0;
};

/**
 * 线程类型
 */
class Thread
{
public:
    using ThreadFunc = std::function<void( int )>; // 线程函数对象类型

private:
    ThreadFunc func_;
    static int generateId_;
    int        threadId_; // 保存线程 ID

public:
    Thread( ThreadFunc func );
    ~Thread();

    /* 启动线程 */
    void start();

    /* 获取线程 ID */
    int getId() const;
};

/**
 * 线程池支持的模式
 */
enum class PoolMode
{
    MODE_FIXED,  // 固定
    MODE_CACHED, // 可变
};

/**
 * 线程池类型
 */
class ThreadPool
{
private:
    std::unordered_map<int, std::unique_ptr<Thread>> threads_; // 线程列表

    int             initThreadSize_;      // 初始的线程数量
    int             threadSizeThreshold_; // 现成数量上线阈值
    std::atomic_int curThreadSize_;       // 当前线程池里面线程数量
    std::atomic_int idleThreadSize_;      // 空闲线程数量

    std::queue<std::shared_ptr<Task>> taskQue_;             // 任务队列
    std::atomic_int                   taskSize_;            // 任务的数量
    int                               taskQueMaxThreshold_; // 任务队列数量上线

    std::mutex              taskQueMtx_; // 保证任务队列的线程安全
    std::condition_variable notFull_;    // 任务队列不满
    std::condition_variable notEmpty_;   // 任务队列不空
    std::condition_variable exitCond_;   // 等待线程资源全部回收

    PoolMode         poolMode_;      // 当前线程池的工作模式
    std::atomic_bool isPoolRunning_; // 当前线程池的启动状态

public:
    ThreadPool();
    ~ThreadPool();
    ThreadPool( const ThreadPool& )            = delete;
    ThreadPool& operator=( const ThreadPool& ) = delete;

    /* 设置线程池的工作模式 */
    void setMode( PoolMode mode );

    /* 设置 task 任务队列上线阈值 */
    void setTaskQueMaxThreshold( int threshold );

    /* 设置线程池 cached 模式下线程阈值 */
    void setThreadSizeThreshold( int threshold );

    /* 给线程池提交任务 */
    Result submitTask( std::shared_ptr<Task> sp );

    /* 开启线程池 */
    void start( int initThreadSize = std::thread::hardware_concurrency() );

private:
    /* 定义线程函数，线程池的所有线程从任务队列里面消费任务，线程函数返回时，相应的线程结束 */
    void threadFunc( int threadId );

    /* 检查 pool 运行状态 */
    bool checkRunningState() const;
};

#endif